#include "DirectorTrabajos.h"
#include "ColaPriorizacion.h"
#include "DirectorProcesos.h"

/* =============================================================================
 * Declaracion Atributos privados
 * =============================================================================
 */
struct DirectorTrabajos{
    tColaPriorizacion cola;
    tDirectorProcesos directorProcesos;
    int nodoContador;
};

typedef struct DirectorTrabajos* _tDirectorTrabajos;

/*==============================================================================
 * Declaracion de metodos privados
 *==============================================================================
 */

static void imprimirColaPriorizacion (tColaPriorizacion pColaPriorizacion, tOutStream pOutStream);

static void imprimirNodosEnjecucion (tDirectorTrabajos pDirectorTrabajos, tOutStream pOutStream);

/*==============================================================================
 * Definicion de metodos publicos
 *==============================================================================
 */

void directorTrabajosCrear (tDirectorTrabajos* pDirectorTrabajos){

    _tDirectorTrabajos director = NULL;
    
    if (pDirectorTrabajos)
    {
        director = (_tDirectorTrabajos) malloc (sizeof (struct DirectorTrabajos));
        if (director)
        {
            colaPriorizacionCrear(&(director->cola));
            directorProcesosCrear(&(director->directorProcesos));
            director->nodoContador = -1;
        }
        *pDirectorTrabajos = director;
    }
}

//------------------------------------------------------------------------------

void directorTrabajosDestruir (tDirectorTrabajos pDirectorTrabajos){
    
    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if (pDirectorTrabajos)
    {
        colaPriorizacionDestruir(director->cola);
        directorProcesosDestruir(director->directorProcesos);
        
        free (director);
    }
}

//------------------------------------------------------------------------------

void directorTrabajosNode (tDirectorTrabajos pDirectorTrabajos, unsigned long int pMemoriaDisponible){
    
    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if (pDirectorTrabajos)
    {
        director->nodoContador++;
        directorProcesosDeclararNodo(director->directorProcesos, director->nodoContador, pMemoriaDisponible);
    }
    directorTrabajosOn(pDirectorTrabajos, director->nodoContador);
}

//------------------------------------------------------------------------------

void directorTrabajosJob (tDirectorTrabajos pDirectorTrabajos
                        , int pPrioridad
                        , int pPotenciaProceso
                        , unsigned long int pRequerimientoMemoria
                        , char* pPathEjecutable
                        , tTiempo pTiempoEjecucion)
{
    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if (pDirectorTrabajos)
    {
        // Instancio el trabajo.
        tTrabajo trabajo;
        trabajoCrear(&trabajo, pPrioridad, pPotenciaProceso, pRequerimientoMemoria, pPathEjecutable, pTiempoEjecucion);
        
        //Priorizo el trabajo.
        colaPriorizacionPriorizar(director->cola, trabajo);
    }
}

//------------------------------------------------------------------------------

void directorTrabajosOn (tDirectorTrabajos pDirectorTrabajos, int pNodoId){
    
    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if(pDirectorTrabajos)
       directorProcesosEncenderNodo(director->directorProcesos, pNodoId);
}

//------------------------------------------------------------------------------

void directorTrabajosOff (tDirectorTrabajos pDirectorTrabajos, int pNodoId){

    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if(pDirectorTrabajos)
        directorProcesosApagarNodo(director->directorProcesos, pNodoId);

}

//------------------------------------------------------------------------------

void directorTrabajosQuery(tDirectorTrabajos pDirectorTrabajos, int pNodoId){
    
    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if (pDirectorTrabajos)
        directorProcesosQueryNodo(director->directorProcesos, pNodoId);
}

//------------------------------------------------------------------------------

void directorTrabajosRefrescar (tDirectorTrabajos pDirectorTrabajos){

    _tDirectorTrabajos director = (_tDirectorTrabajos) pDirectorTrabajos;
    
    if (pDirectorTrabajos)
    {
        // Obtengo los trabajos en la cola de priorizacion segun el orden de
        // prioridad y los ejecuto mediante el director de procesos.
        
        tColaPriorizacionIterador iteradorCola = colaPriorizacionIterador(director->cola);
        while (colaPriorizacionIteradorMoverSiguiente(iteradorCola))
        {
            tTrabajo trabajo = (tTrabajo) colaPriorizacionIteradorActual(iteradorCola);
            
            directorProcesosEjecutarTrabajo(director->directorProcesos, trabajo);
        }
        colaPriorizacionIteradorLiberar(iteradorCola);
        
        // Debo remover los trabajos que se encuentran en ejecucion de la cola de
        // priorizacion.
        
        // Obtengo del director de procesos una lista de los trabajos que se encuentran
        // en ejecucion.

        tLista trabajosEnEjecucion;
        listaCrear(&trabajosEnEjecucion, &DestructorDato);
        directorProcesosGetTrabajosEnEjecucion(director->directorProcesos, trabajosEnEjecucion);
        
        // Para todo trabajo que se encuentre en ejecucion, lo remuevo de la cola de priorizacion.
        
        tIteradorLista iteradorTrabajosEnEjecucion = listaObtenerIterador(trabajosEnEjecucion);
        while (listaIteradorMoverSiguiente(iteradorTrabajosEnEjecucion))
        {
            tTrabajo trabajoEnEjecucion = listaIteradorActual(iteradorTrabajosEnEjecucion);

            colaPriorizacionRemover(director->cola, trabajoEnEjecucion);
        }
        listaLiberarIterador(iteradorTrabajosEnEjecucion);

        listaDestruir(trabajosEnEjecucion);
    }
}

//------------------------------------------------------------------------------

void directorTrabajosImprimir(tDirectorTrabajos pDirectorTrabajos, tOutStream pOutStream){
    if (pDirectorTrabajos && pOutStream)
    {
        imprimirColaPriorizacion(((_tDirectorTrabajos)pDirectorTrabajos)->cola, pOutStream);
        fprintf (pOutStream, "\n");
        imprimirNodosEnjecucion(pDirectorTrabajos, pOutStream);
    }
}

//------------------------------------------------------------------------------

static void imprimirColaPriorizacion (tColaPriorizacion pColaPriorizacion, tOutStream pOutStream){

    if (pColaPriorizacion)
    {
        // Imprimo la lista de priorizacion.
       tColaPriorizacionIterador iteradorCola = colaPriorizacionIterador(pColaPriorizacion);
       while (colaPriorizacionIteradorMoverSiguiente(iteradorCola))
       {
           tTrabajo trabajo = colaPriorizacionIteradorActual(iteradorCola);
           fprintf (pOutStream, "\n");
           trabajoImprimir(trabajo, pOutStream);
       }
       colaPriorizacionIteradorLiberar(iteradorCola);       
    }
}

//------------------------------------------------------------------------------

static void imprimirNodosEnjecucion (tDirectorTrabajos pDirectorTrabajos, tOutStream pOutStream){
    
    if (pDirectorTrabajos && pOutStream)
    {
        _tDirectorTrabajos director = (_tDirectorTrabajos)pDirectorTrabajos;
        directorProcesosImprimir (director->directorProcesos, pOutStream);
    }
}


